//
// Created by twetec on 25-7-21.
//

#include "handle_mysql_probe_task.h"

#include <boost/json.hpp>
#include <mysql/mysql.h>
#include <base64/base64.h>

#include <bs_thread_pool/BS_thread_pool.hpp>

#include <network_prober/utils/constants.h>

using namespace std::chrono_literals;

namespace network_prober::probe
{
// 线程池
static BS::thread_pool s_iopool{1000};

// MySQLProbeIPv4::MySQLProbeIPv4(
//     std::string_view interface,
//     std::string_view target,
//     std::uint32_t port,
//     std::string_view userName,
//     std::string_view password,
//     std::string_view databaseName,
//     std::string_view queryStatement
// )
// : m_interface(interface), m_target(target), m_port(port), m_userName(userName),
// m_password(password), m_databaseName(databaseName), m_queryStatement(queryStatement)
// {
//
// }
//
// void MySQLProbeIPv4::setOnProbedCallback(std::function<void(std::int64_t)> callback)
// {
//     m_onProbedCallback = std::move(callback);
// }
//
// void MySQLProbeIPv4::probe()
// {
//     // 建立连接时，开始计时
//     m_probeStartTime = std::chrono::steady_clock::now();
//
//     // 指向当前对象的shared_ptr
//     auto self{shared_from_this()};
//
//     // 发起探测
//     m_onProbedCallbackFuture = std::async(std::launch::async, [this, self] {
//         // 初始化数据库连接
//         MYSQL* connPtr = mysql_init(nullptr);
//         // 如果初始化失败，则设置延迟为-1
//         if (!connPtr) {
//             // 错误信息
//             SPDLOG_INFO("MySQL观测目标连接初始化失败：{}", mysql_error(connPtr));
//             // 关闭连接
//             mysql_close(connPtr);
//             // 回调结果
//             m_onProbedCallback(-1);
//             // 结束后续执行
//             return;
//         }
//
//         // 设置字符编码
//         mysql_options(connPtr, MYSQL_SET_CHARSET_NAME, "utf8");
//         // 设置客户端网口
//         mysql_options(connPtr, MYSQL_OPT_BIND, m_interface.c_str());
//         // 设置自动重连
//         mysql_options(connPtr, MYSQL_OPT_CONNECT_TIMEOUT, "13");
//
//         // 连接数据库 如果连接失败，则设置延迟为-1
//         if (mysql_real_connect(connPtr, m_target.c_str(), m_userName.c_str(), m_password.c_str(), m_databaseName.c_str(), m_port, NULL, 0) == NULL) {
//             // 错误信息
//             SPDLOG_INFO("MySQL观测目标连接失败：{}", mysql_error(connPtr));
//             // 回调结果
//             m_onProbedCallback(-1);
//             // 关闭连接
//             mysql_close(connPtr);
//             // 结束后续执行
//             return;
//         }
//
//         // 构建SQL语句
//         const char* sql = m_queryStatement.empty()? "SELECT 1" : m_queryStatement.c_str();
//
//         // 发送查询语句，如果查询结果出错，则延迟为-1
//         if (mysql_query(connPtr, sql) != 0) {
//             // 错误信息
//             SPDLOG_INFO("MySQL观测目标查询失败：{}", mysql_error(connPtr));
//             // 关闭连接
//             mysql_close(connPtr);
//             // 回调结果
//             m_onProbedCallback(-1);
//             // 结束后续执行
//             return;
//         }
//
//         // 关闭连接
//         mysql_close(connPtr);
//
//         // 回调结果
//         m_onProbedCallback(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - m_probeStartTime).count());
//     });
// }
//
// MySQLProbeIPv4::~MySQLProbeIPv4()
// {
//
// }

HandleMySQLProbeIPv4Awaiter::HandleMySQLProbeIPv4Awaiter(const database::ProbeTaskModel &probeTask)
: m_interface(probeTask.interface), m_target(probeTask.address), m_port(probeTask.port), m_userName(probeTask.userName),
m_password(probeTask.password), m_databaseName(probeTask.databaseName), m_queryStatement(probeTask.queryStatement)
{
}

bool HandleMySQLProbeIPv4Awaiter::await_ready()
{
    return false;
}

void HandleMySQLProbeIPv4Awaiter::await_suspend(std::coroutine_handle<> handle)
{
    s_iopool.submit_task([this, handle] {
        // 线程锁
        std::mutex mtx;
        std::condition_variable cv;

        // 请求计时 - 开始时间
        std::chrono::time_point<std::chrono::steady_clock> probeStartTime = std::chrono::steady_clock::now();

        // 发起探测
        std::future future = std::async(std::launch::async, [this, &probeStartTime, &mtx, &cv] {
            // 初始化数据库连接
            MYSQL* connPtr = mysql_init(nullptr);
            // 如果初始化失败，则设置延迟为-1
            if (!connPtr) {
                // 错误信息
                SPDLOG_INFO("MySQL观测目标连接初始化失败：{}", mysql_error(connPtr));
                // 关闭连接
                mysql_close(connPtr);
                // 加锁
                std::unique_lock<std::mutex> lock(mtx);
                // 保存延迟
                m_delay = -1;
                // 通知延迟保存成功
                cv.notify_one();
                // 结束后续执行
                return;
            }

            // 设置字符编码
            mysql_options(connPtr, MYSQL_SET_CHARSET_NAME, "utf8");
            // 设置客户端网口
            mysql_options(connPtr, MYSQL_OPT_BIND, m_interface.c_str());
            // 设置自动重连
            mysql_options(connPtr, MYSQL_OPT_CONNECT_TIMEOUT, "6");

            // 连接数据库 如果连接失败，则设置延迟为-1
            if (mysql_real_connect(connPtr, m_target.c_str(), m_userName.c_str(), m_password.c_str(), m_databaseName.c_str(), m_port, NULL, 0) == NULL) {
                // 错误信息
                SPDLOG_INFO("MySQL观测目标连接失败：{}", mysql_error(connPtr));
                // 关闭连接
                mysql_close(connPtr);
                // 加锁
                std::unique_lock<std::mutex> lock(mtx);
                // 保存延迟
                m_delay = -1;
                // 通知延迟保存成功
                cv.notify_one();
                // 结束后续执行
                return;
            }

            // 构建SQL语句
            const char* sql = m_queryStatement.empty()? "SELECT 1" : m_queryStatement.c_str();

            // 发送查询语句，如果查询结果出错，则延迟为-1
            if (mysql_query(connPtr, sql) != 0) {
                // 错误信息
                SPDLOG_INFO("MySQL观测目标查询失败：{}", mysql_error(connPtr));
                // 关闭连接
                mysql_close(connPtr);
                // 加锁
                std::unique_lock<std::mutex> lock(mtx);
                // 保存延迟
                m_delay = -1;
                // 通知延迟保存成功
                cv.notify_one();
                // 结束后续执行
                return;
            }

             // 关闭连接
             mysql_close(connPtr);

            // 加锁
            std::unique_lock<std::mutex> lock(mtx);
            // 保存延迟
            m_delay = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - probeStartTime).count();
            // 通知延迟保存成功
            cv.notify_one();
        });

        // 等待响应（12s）
        std::unique_lock<std::mutex> lock(mtx);
        std::cv_status cvStatus = cv.wait_for(lock, 8s);

        // 如果等待超时,则将延迟置为-1
        if (cvStatus == std::cv_status::timeout) m_delay = -1;

        // 恢复暂停的协程
        handle.resume();
    });
}

std::int64_t HandleMySQLProbeIPv4Awaiter::await_resume()
{
    return m_delay;
}


// MySQLProbeIPv6::MySQLProbeIPv6(
//     std::string_view interface,
//     std::string_view target,
//     std::uint32_t port,
//     std::string_view userName,
//     std::string_view password,
//     std::string_view databaseName,
//     std::string_view queryStatement
// )
// : m_interface(interface), m_target(target), m_port(port), m_userName(userName),
// m_password(password), m_databaseName(databaseName), m_queryStatement(queryStatement)
// {
//
// }
//
// void MySQLProbeIPv6::setOnProbedCallback(std::function<void(std::int64_t)> callback)
// {
//     m_onProbedCallback = std::move(callback);
// }
//
// void MySQLProbeIPv6::probe()
// {
//     // 建立连接时，开始计时
//     m_probeStartTime = std::chrono::steady_clock::now();
//
//     // 指向当前对象的shared_ptr
//     auto self{shared_from_this()};
//
//     // 发起探测
//     m_onProbedCallbackFuture = std::async(std::launch::async, [this, self] {
//         // 初始化数据库连接
//         MYSQL* connPtr = mysql_init(nullptr);
//         // 如果初始化失败，则设置延迟为-1
//         if (!connPtr) {
//             // 错误信息
//             SPDLOG_INFO("MySQL观测目标连接初始化失败：{}", mysql_error(connPtr));
//             // 关闭连接
//             mysql_close(connPtr);
//             // 回调结果
//             m_onProbedCallback(-1);
//             // 结束后续执行
//             return;
//         }
//
//         // 设置字符编码
//         mysql_options(connPtr, MYSQL_SET_CHARSET_NAME, "utf8");
//         // 设置客户端网口
//         mysql_options(connPtr, MYSQL_OPT_BIND, m_interface.c_str());
//         // 设置自动重连
//         mysql_options(connPtr, MYSQL_OPT_CONNECT_TIMEOUT, "13");
//
//         // 连接数据库 如果连接失败，则设置延迟为-1
//         if (mysql_real_connect(connPtr, m_target.c_str(), m_userName.c_str(), m_password.c_str(), m_databaseName.c_str(), m_port, NULL, 0) == NULL) {
//             // 错误信息
//             SPDLOG_INFO("MySQL观测目标连接失败：{}", mysql_error(connPtr));
//             // 回调结果
//             m_onProbedCallback(-1);
//             // 关闭连接
//             mysql_close(connPtr);
//             // 结束后续执行
//             return;
//         }
//
//         // 构建SQL语句
//         const char* sql = m_queryStatement.empty()? "SELECT 1" : m_queryStatement.c_str();
//
//         // 发送查询语句，如果查询结果出错，则延迟为-1
//         if (mysql_query(connPtr, sql) != 0) {
//             // 错误信息
//             SPDLOG_INFO("MySQL观测目标查询失败：{}", mysql_error(connPtr));
//             // 关闭连接
//             mysql_close(connPtr);
//             // 回调结果
//             m_onProbedCallback(-1);
//             // 结束后续执行
//             return;
//         }
//
//         // 关闭连接
//         mysql_close(connPtr);
//
//         // 回调结果
//         m_onProbedCallback(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - m_probeStartTime).count());
//     });
// }
//
// MySQLProbeIPv6::~MySQLProbeIPv6()
// {
// }

HandleMySQLProbeIPv6Awaiter::HandleMySQLProbeIPv6Awaiter(const database::ProbeTaskModel &probeTask)
: m_interface(probeTask.interface), m_target(probeTask.address), m_port(probeTask.port), m_userName(probeTask.userName),
m_password(probeTask.password), m_databaseName(probeTask.databaseName), m_queryStatement(probeTask.queryStatement)
{
}

bool HandleMySQLProbeIPv6Awaiter::await_ready()
{
    return false;
}

void HandleMySQLProbeIPv6Awaiter::await_suspend(std::coroutine_handle<> handle)
{
    s_iopool.submit_task([this, handle] {
        // 线程锁
        std::mutex mtx;
        std::condition_variable cv;

        // 请求计时 - 开始时间
        std::chrono::time_point<std::chrono::steady_clock> probeStartTime = std::chrono::steady_clock::now();

        // 发起探测
        std::future future = std::async(std::launch::async, [this, &probeStartTime, &mtx, &cv] {
            // 初始化数据库连接
            MYSQL* connPtr = mysql_init(nullptr);
            // 如果初始化失败，则设置延迟为-1
            if (!connPtr) {
                // 错误信息
                SPDLOG_INFO("MySQL观测目标连接初始化失败：{}", mysql_error(connPtr));
                // 关闭连接
                mysql_close(connPtr);
                // 加锁
                std::unique_lock<std::mutex> lock(mtx);
                // 保存延迟
                m_delay = -1;
                // 通知延迟保存成功
                cv.notify_one();
                // 结束后续执行
                return;
            }

            // 设置字符编码
            mysql_options(connPtr, MYSQL_SET_CHARSET_NAME, "utf8");
            // 设置客户端网口
            // mysql_options(connPtr, MYSQL_OPT_BIND, m_interface.c_str());
            // 设置自动重连
            mysql_options(connPtr, MYSQL_OPT_CONNECT_TIMEOUT, "6");

            // 连接数据库 如果连接失败，则设置延迟为-1
            if (mysql_real_connect(connPtr, m_target.c_str(), m_userName.c_str(), m_password.c_str(), m_databaseName.c_str(), m_port, NULL, 0) == NULL) {
                // 错误信息
                SPDLOG_INFO("MySQL观测目标连接失败：{}", mysql_error(connPtr));
                // 关闭连接
                mysql_close(connPtr);
                // 加锁
                std::unique_lock<std::mutex> lock(mtx);
                // 保存延迟
                m_delay = -1;
                // 通知延迟保存成功
                cv.notify_one();
                // 结束后续执行
                return;
            }

            // 构建SQL语句
            const char* sql = m_queryStatement.empty()? "SELECT 1" : m_queryStatement.c_str();

            // 发送查询语句，如果查询结果出错，则延迟为-1
            if (mysql_query(connPtr, sql) != 0) {
                // 错误信息
                SPDLOG_INFO("MySQL观测目标查询失败：{}", mysql_error(connPtr));
                // 关闭连接
                mysql_close(connPtr);
                // 加锁
                std::unique_lock<std::mutex> lock(mtx);
                // 保存延迟
                m_delay = -1;
                // 通知延迟保存成功
                cv.notify_one();
                // 结束后续执行
                return;
            }

             // 关闭连接
             mysql_close(connPtr);

            // 加锁
            std::unique_lock<std::mutex> lock(mtx);
            // 保存延迟
            m_delay = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - probeStartTime).count();
            // 通知延迟保存成功
            cv.notify_one();
        });

        // 等待响应（12s）
        std::unique_lock<std::mutex> lock(mtx);
        std::cv_status cvStatus = cv.wait_for(lock, 8s);

        // 如果等待超时,则将延迟置为-1
        if (cvStatus == std::cv_status::timeout) m_delay = -1;

        // 恢复暂停的协程
        handle.resume();
    });
}

std::int64_t HandleMySQLProbeIPv6Awaiter::await_resume()
{
    return m_delay;
}

}
